<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="p8543" id="p8543"><span data-lake-id="uff863d1e" id="uff863d1e">典型回答</span></h1>
  <p data-lake-id="u68039037" id="u68039037"><strong><span data-lake-id="u05517ad8" id="u05517ad8">在Java中，实现动态代理有两种方式：</span></strong></p>
  <ol list="u153054ee">
   <li fid="u847e455e" data-lake-id="u8722ce97" id="u8722ce97"><strong><span data-lake-id="u8001ba4a" id="u8001ba4a">JDK动态代理</span></strong><span data-lake-id="u7bb2419e" id="u7bb2419e">：Java.lang.reflect 包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。</span></li>
   <li fid="u847e455e" data-lake-id="u4ddfd0e6" id="u4ddfd0e6"><strong><span data-lake-id="u20440134" id="u20440134">Cglib动态代理</span></strong><span data-lake-id="u9aa83f2c" id="u9aa83f2c">：Cglib (Code Generation Library )是一个第三方代码生成类库，运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。</span></li>
  </ol>
  <p data-lake-id="u48ef3f4f" id="u48ef3f4f"><br></p>
  <p data-lake-id="ubb70ca06" id="ubb70ca06"><br></p>
  <p data-lake-id="u160f5061" id="u160f5061"><strong><span data-lake-id="u8e768233" id="u8e768233">JDK动态代理和Cglib动态代理的区别：</span></strong></p>
  <p data-lake-id="uffb43f94" id="uffb43f94"><strong><span data-lake-id="ua4f5349f" id="ua4f5349f">​</span></strong><br></p>
  <p data-lake-id="ufcdee873" id="ufcdee873"><span data-lake-id="u9013a055" id="u9013a055">JDK的动态代理有一个限制，就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类，就可以使用CGLIB实现。</span></p>
  <p data-lake-id="ube5e9376" id="ube5e9376"><span data-lake-id="u2189905a" id="u2189905a">​</span><br></p>
  <p data-lake-id="u2fd271ec" id="u2fd271ec"><span data-lake-id="ud7b91904" id="ud7b91904">Cglib是一个强大的高性能的代码生成包，它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用，例如Spring AOP和dynaop，为他们提供方法的interception（拦截）。</span></p>
  <p data-lake-id="u83673b7e" id="u83673b7e"><span data-lake-id="u4ea6ded9" id="u4ea6ded9">​</span><br></p>
  <p data-lake-id="u6b5558ce" id="u6b5558ce"><span data-lake-id="u02097c4a" id="u02097c4a">Cglib包的底层是通过使用一个小而快的字节码处理框架ASM，来转换字节码并生成新的类。不鼓励直接使用ASM，因为它需要你对JVM内部结构包括class文件的格式和指令集都很熟悉。</span></p>
  <p data-lake-id="u4b6e2ac8" id="u4b6e2ac8"><br></p>
  <p data-lake-id="ub31f5914" id="ub31f5914"><strong><span data-lake-id="ua0df022a" id="ua0df022a">所以，使用JDK动态代理的对象必须实现一个或多个接口；而使用cglib代理的对象则无需实现接口，达到代理类无侵入。</span></strong></p>
  <h1 data-lake-id="T6l2g" id="T6l2g"><span data-lake-id="u57e38dc9" id="u57e38dc9">拓展知识</span></h1>
  <h2 data-lake-id="dfuwn" id="dfuwn"><span data-lake-id="u947b1da9" id="u947b1da9">静态代理和动态代理的区别</span></h2>
  <p data-lake-id="u6b6f0707" id="u6b6f0707"><span data-lake-id="u23e25e5d" id="u23e25e5d">最大的区别就是静态代理是编译期确定的，但是动态代理却是运行期确定的。</span></p>
  <p data-lake-id="u7a938ca0" id="u7a938ca0"><span data-lake-id="ud935f9c7" id="ud935f9c7">​</span><br></p>
  <p data-lake-id="u76eaecf9" id="u76eaecf9"><span data-lake-id="u3df35618" id="u3df35618">同时，使用静态代理模式需要程序员手写很多代码，这个过程是比较浪费时间和精力的。一旦需要代理的类中方法比较多，或者需要同时代理多个对象的时候，这无疑会增加很大的复杂度。</span></p>
  <p data-lake-id="ud935a50f" id="ud935a50f"><span data-lake-id="ua3ec5fcb" id="ua3ec5fcb">​</span><br></p>
  <p data-lake-id="uc931b82b" id="uc931b82b"><span data-lake-id="u7dbc7795" id="u7dbc7795">反射是动态代理的实现方式之一。</span></p>
  <p data-lake-id="u70feff42" id="u70feff42"><span data-lake-id="u899c525f" id="u899c525f">​</span><br></p>
  <h2 data-lake-id="Vwqo8" id="Vwqo8"><span data-lake-id="u69683c41" id="u69683c41">动态代理的用途</span></h2>
  <p data-lake-id="uba46d531" id="uba46d531"><br></p>
  <p data-lake-id="udeb9eb0b" id="udeb9eb0b"><span data-lake-id="ueb768413" id="ueb768413">Java的动态代理，在日常开发中可能并不经常使用，但是并不代表他不重要。</span><strong><span data-lake-id="ua55c46d8" id="ua55c46d8">Java的动态代理的最主要的用途就是应用在各种框架中。因为使用动态代理可以很方便的运行期生成代理类，通过代理类可以做很多事情，比如AOP，比如过滤器、拦截器等。</span></strong></p>
  <p data-lake-id="ubd17aa41" id="ubd17aa41"><span data-lake-id="u0693a4d4" id="u0693a4d4">​</span><br></p>
  <p data-lake-id="ubf9975bf" id="ubf9975bf"><span data-lake-id="u4d2c0ddb" id="u4d2c0ddb">在我们平时使用的框架中，像servlet的filter、包括spring提供的aop以及struts2的拦截器都使用了动态代理功能。我们日常看到的mybatis分页插件，以及日志拦截、事务拦截、权限拦截这些几乎全部由动态代理的身影。</span></p>
  <h2 data-lake-id="DC99m" id="DC99m"><span data-lake-id="u93e90556" id="u93e90556">Spring AOP的实现方式</span></h2>
  <p data-lake-id="u057a44f4" id="u057a44f4"><span data-lake-id="u7203aea3" id="u7203aea3">Spring AOP中的动态代理主要有两种方式，JDK动态代理和CGLIB动态代理。</span></p>
  <p data-lake-id="u87ee30fb" id="u87ee30fb"><span data-lake-id="u6b10574b" id="u6b10574b">​</span><br></p>
  <p data-lake-id="u3b0fb67b" id="u3b0fb67b"><span data-lake-id="u4d3c5154" id="u4d3c5154">JDK动态代理通过反射来接收被代理的类，并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。</span></p>
  <p data-lake-id="u25a3418e" id="u25a3418e"><span data-lake-id="u8723f435" id="u8723f435">​</span><br></p>
  <p data-lake-id="u42f10566" id="u42f10566"><span data-lake-id="u136cb5af" id="u136cb5af">如果目标类没有实现接口，那么Spring AOP会选择使用CGLIB来动态代理目标类。</span></p>
  <p data-lake-id="u63996066" id="u63996066"><span data-lake-id="u0210327e" id="u0210327e">​</span><br></p>
  <p data-lake-id="u397a6f9c" id="u397a6f9c"><span data-lake-id="ud727c1d3" id="ud727c1d3">CGLIB（Code Generation Library），是一个代码生成的类库，可以在运行时动态的生成某个类的子类，注意，CGLIB是通过继承的方式做的动态代理，因此如果某个类被标记为final，那么它是无法使用CGLIB做动态代理的。</span></p>
  <h2 data-lake-id="jwGcc" id="jwGcc"><span data-lake-id="u7be4e655" id="u7be4e655">JDK 动态代理的代码段</span></h2>
  <pre lang="java"><code>
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        // TODO Auto-generated method stub
        System.out.println("--------------------add----------------------");
    }
}

public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    public MyInvocationHandler(Object target) {
        super();
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        PerformanceMonior.begin(target.getClass().getName()+"."+method.getName());
        //System.out.println("-----------------begin "+method.getName()+"-----------------");
        Object result = method.invoke(target, args);
        //System.out.println("-----------------end "+method.getName()+"-----------------");
        PerformanceMonior.end();
        return result;
    }
    public Object getProxy(){
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
    }
}
public static void main(String[] args) {
    UserService service = new UserServiceImpl();
    MyInvocationHandler handler = new MyInvocationHandler(service);
    UserService proxy = (UserService) handler.getProxy();
    proxy.add();
}
</code></pre>
  <h2 data-lake-id="mqLvg" id="mqLvg"><span data-lake-id="uca5d5a34" id="uca5d5a34">Cglib动态代理的代码段</span></h2>
  <pre lang="java"><code>
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        // TODO Auto-generated method stub
        System.out.println("--------------------add----------------------");
    }
}
public class CglibProxy implements MethodInterceptor{ 
    private Enhancer enhancer = new Enhancer(); 
    public Object getProxy(Class clazz){ 
        //设置需要创建子类的类 
        enhancer.setSuperclass(clazz); 
        enhancer.setCallback(this); 
        //通过字节码技术动态创建子类实例 
        return enhancer.create(); 
    } 
    //实现MethodInterceptor接口方法 
    public Object intercept(Object obj, Method method, Object[] args, 
        MethodProxy proxy) throws Throwable { 
        System.out.println("前置代理"); 
        //通过代理类调用父类中的方法 
        Object result = proxy.invokeSuper(obj, args); 
        System.out.println("后置代理"); 
        return result; 
    } 
} 
public class DoCGLib { 
    public static void main(String[] args) { 
        CglibProxy proxy = new CglibProxy(); 
        //通过生成子类的方式创建代理类 
        UserServiceImpl proxyImp = (UserServiceImpl)proxy.getProxy(UserServiceImpl.class); 
        proxyImp.add(); 
    } 
}
</code></pre>
 </body>
</html>